#include "stdafx.h"
#include "Exceptions.h"
#include "NDISManagedWifiContext.h"
#include <stdio.h>
#include <ntddndis.h>

#pragma comment (lib,"wlanapi.lib")

using namespace System::Runtime::InteropServices;
using namespace System::Collections::Generic;
using namespace System::Net::NetworkInformation;

namespace ManagedWifi {
	
	NDISManagedWifiContext::NDISManagedWifiContext(){
		this->_devicePrefix = "\\\\.\\";
		this->IoctlNdisQueryGlobalStats = 0x00170002;
		this->_os= (Environment::OSVersion->Version->Major) < 6 ? NDISManagedWifiContext::OS::WindowsXP : NDISManagedWifiContext::OS::WindowsVista;
	}
		
	NDISManagedWifiContext::~NDISManagedWifiContext(){

	}
		
	IEnumerable<IInterface^> ^ NDISManagedWifiContext::Interfaces::get(){
		return nullptr;		
	}
		
	IEnumerable<INetwork ^> ^ NDISManagedWifiContext::GetAvailableNetworks(IInterface ^ wlan_interface){
		
		String ^ device_string = String::Format("{0}{{{1}}}",(String ^)_devicePrefix,wlan_interface->Guid.ToString()->ToUpper());

		//Console::WriteLine(device_string);
		IntPtr string_ptr = Marshal::StringToHGlobalUni(device_string);
		wprintf((LPCWSTR)string_ptr.ToPointer());

		HANDLE deviceHandle = CreateFile((LPCWSTR)string_ptr.ToPointer(),0,FILE_SHARE_READ | FILE_SHARE_WRITE, 0,OPEN_EXISTING,0,0);
		
		if(deviceHandle == INVALID_HANDLE_VALUE){
			throw gcnew WlanApiException("Could not open handle to device");
		}

		const int memSize = 65536;
		IntPtr bssidPtr = Marshal::AllocHGlobal(memSize);

		DWORD bytesReturned = 0;

		bool success = QueryGlobalStats(
                        deviceHandle,
						OID_DOT11_ENUM_BSS_LIST,
						bssidPtr.ToPointer(),
                        memSize,
                        &bytesReturned
                    );
		
		
		NDIS_802_11_BSSID_LIST * list;

		list = (NDIS_802_11_BSSID_LIST *)bssidPtr.ToPointer();
		ULONG items = list->NumberOfItems;
		NDIS_WLAN_BSSID_EX * curr_item = ((NDIS_WLAN_BSSID_EX *) list->Bssid);

		for(DWORD i=0; i<items;i++){
			
			DOT11_MAC_ADDRESS mac[6];
			memcpy(mac, curr_item->MacAddress,sizeof(DOT11_MAC_ADDRESS));

			Console::WriteLine("\n{0:x2}:{1:x2}:{2:x2}:{3:x2}:{4:x2}:{5:x2}", (byte)mac[0],(byte)mac[1],(byte)mac[2],(byte)mac[3],(byte)mac[4],(byte)mac[5]);
			
			//curr_item = curr_item + curr_item->Length;
		}

		DOT11_MAC_ADDRESS mac[6];

		
		printf((char *)&(list->Bssid->Ssid));
		//);

		


		Marshal::FreeHGlobal(bssidPtr);
		Marshal::FreeHGlobal(string_ptr);

		return nullptr;
	}
		

	bool NDISManagedWifiContext::QueryGlobalStats(HANDLE deviceHandle, DWORD oidCode, void * buffer, int bufferSize, LPDWORD bytesRead)
        {
            bool result;    // function return value

            //
            // Allocate a buffer to hold the OID code that
            // will be passed to the driver.
            //
            IntPtr oidPtr = Marshal::AllocHGlobal(sizeof(int));
            try {
                // Get a pointer to the OID code
                Marshal::WriteInt32(oidPtr, (int)oidCode);
                //
                // We successfully opened the driver, format the IOCTL to pass the
                // driver.
                //
                result = DeviceIoControl(
                        deviceHandle,
						IOCTL_NDIS_QUERY_GLOBAL_STATS,
						oidPtr.ToPointer(),
                        sizeof(DWORD),
						buffer,
                        bufferSize,
                        bytesRead,
                        0);

				Console::WriteLine("Bytes read {0}",*bytesRead);
                if (!result) {
                    Console::WriteLine("DeviceIoControl failed. Error = " + Marshal::GetLastWin32Error());
                }

            }
            finally {
                // Make sure the memory is freed
                Marshal::FreeHGlobal(oidPtr);
            }
            return (result);
        }

	void NDISManagedWifiContext::Scan(IInterface ^ wlan_interface){

	}

	Guid NDISManagedWifiContext::FromGUID( _GUID& guid ) {
	return Guid( guid.Data1, guid.Data2, guid.Data3, 
		guid.Data4[ 0 ], guid.Data4[ 1 ], 
		guid.Data4[ 2 ], guid.Data4[ 3 ], 
		guid.Data4[ 4 ], guid.Data4[ 5 ], 
		guid.Data4[ 6 ], guid.Data4[ 7 ] );
	}

	_GUID NDISManagedWifiContext::ToGUID( Guid& guid ) {
	array<Byte>^ guidData = guid.ToByteArray();
	pin_ptr<Byte> data = &(guidData[ 0 ]);

	return *(_GUID *)data;
	}
}